/*
 * Copyright (C) 2010 Moduad Co., Ltd.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.androidpn.server.xmpp.handler;

import java.util.List;
import java.util.Set;

import org.androidpn.server.entity.Role;
import org.androidpn.server.entity.Room;
import org.androidpn.server.entity.User;
import org.androidpn.server.entity.Room.RoomStatus;
import org.androidpn.server.service.RoleService;
import org.androidpn.server.service.RoomService;
import org.androidpn.server.service.ServiceLocator;
import org.androidpn.server.service.UserService;
import org.androidpn.server.xmpp.UnauthorizedException;
import org.androidpn.server.xmpp.packet.RoomPacket;
import org.androidpn.server.xmpp.packet.RoomPacket.Operation;
import org.androidpn.server.xmpp.push.PushRoomToClientThread;
import org.androidpn.server.xmpp.session.ClientSession;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.smack.util.StringUtils;
import org.xmpp.packet.IQ;
import org.xmpp.packet.PacketError;

/**
 * This class is to handle the TYPE_IQ jabber:iq:roster protocol.
 * 
 * @author Sehwan Noh (devnoh@gmail.com)
 */
public class IQRoomHandler extends IQHandler {

	private static final String NAMESPACE = "jabber:iq:room";

	private RoleService roleService;

	private RoomService roomService;

	private UserService userService;

	/**
	 * Constructor.
	 */
	public IQRoomHandler() {
		roleService = (RoleService) ServiceLocator
				.getService(ServiceLocator.ROLE_SERVICE);
		roomService = (RoomService) ServiceLocator
				.getService(ServiceLocator.ROOM_SERVICE);
		userService = ServiceLocator.getUserService();
	}

	/**
	 * Handles the received IQ packet.
	 * 
	 * @param packet
	 *            the packet
	 * @return the response to send back
	 * @throws UnauthorizedException
	 *             if the user is not authorized
	 */
	public IQ handleIQ(IQ packet) throws UnauthorizedException {
		IQ reply = null;

		ClientSession session = sessionManager.getSession(packet.getFrom());

		try {
			Element query = packet.getChildElement();
			reply = IQ.createResultIQ(packet);
			String operationStr = query.elementText("operation");
			if (operationStr != null && !operationStr.equals("")) {
				Operation operation = Operation.valueOf(operationStr);
				switch (operation) {
				case createRoom:
					createRoom(reply, query);
					break;
				case getOnlineRooms:
					getOnlineRooms(reply);
					break;
				case joinRoom:
					joinRoom(reply, query);
					break;
				case quitRoom:
					quitRoom(query);
					break;
				case updateRoom:
					updateRoom(reply, query);
					break;
				case startGame:
					startGame(query);
					break;
				default:
					reply.setError(PacketError.Condition.feature_not_implemented);
					break;
				}
			} else {
				reply = null;
			}
		} catch (Exception e) {
			log.error(e.getMessage());
			reply.setError(PacketError.Condition.feature_not_implemented);
		}
		if (reply != null) {
			session.process(reply);
		}
		return null;
	}

	private void startGame(Element query) {
		String roomXML = StringUtils.unescapeNode(query.elementText("room"));
		Room room = Room.fromXML(roomXML);
		room = roomService.find(room.getId());
		room.setStatus(RoomStatus.inGame);
		roomService.update(room);
		new Thread(new PushRoomToClientThread(room.getId(), sessionManager))
				.start();
	}

	/**
	 * 更新房间信息
	 * 
	 * @param reply
	 * @param query
	 * @throws DocumentException
	 */
	private void updateRoom(IQ reply, Element query) throws DocumentException {
		String roomXML = StringUtils.unescapeNode(query.elementText("room"));
		Room room = Room.fromXML(roomXML);
		room = roomService.find(room.getId());
		RoomPacket roomPacket = new RoomPacket();
		roomPacket.setRoom(room);
		if (roomPacket.getChildElementXML() != null) {
			Document doc = DocumentHelper.parseText(roomPacket
					.getChildElementXML());
			Element element = doc.getRootElement();
			reply.setChildElement(element.createCopy());
			reply.setType(IQ.Type.result);
		}
	}

	/**
	 * 加入房间
	 * 
	 * @param reply
	 * @param query
	 * @throws DocumentException
	 */
	private void joinRoom(IQ reply, Element query) throws DocumentException {
		String roomXML = StringUtils.unescapeNode(query.elementText("room"));
		Room room = Room.fromXML(roomXML);
		Set<Role> roles = room.getRoles();
		for (Role role : roles) {
			room = roomService.joinRoom(role.getId(), room.getId());
			break;
		}
		RoomPacket roomPacket = new RoomPacket();
		roomPacket.setRoom(room);
		if (roomPacket.getChildElementXML() != null) {
			Document doc = DocumentHelper.parseText(roomPacket
					.getChildElementXML());
			Element element = doc.getRootElement();
			reply.setChildElement(element.createCopy());
			reply.setType(IQ.Type.result);
			new Thread(new PushRoomToClientThread(room.getId(), sessionManager))
					.start();
		}
	}

	/**
	 * 退出游戏房间
	 * 
	 * @param query
	 */
	private void quitRoom(Element query) {
		String roomXML = StringUtils.unescapeNode(query.elementText("room"));
		Room room = Room.fromXML(roomXML);
		Set<Role> roles = room.getRoles();
		for (Role role : roles) {
			roomService.quitRoom(role.getId(), room.getId());
			break;
		}
		new Thread(new PushRoomToClientThread(room.getId(), sessionManager))
				.start();
	}

	/**
	 * 获取在线房间信息
	 * 
	 * @param reply
	 * @throws DocumentException
	 */
	private void getOnlineRooms(IQ reply) throws DocumentException {
		RoomPacket roomPacket = new RoomPacket();
		List<Room> rooms = roomService.getOnlineRooms();
		// 删除空的房间
		for (Room room : rooms) {
			for (Role role : room.getRoles()) {
				User user = role.getUser();
				ClientSession session = sessionManager.getSession(user
						.getUsername().toLowerCase());
				if (session == null) {
					room.getRoles().remove(role);
				}
			}
			roomService.update(room);
			if (room.getRoles().size() <= 0) {
				roomService.delete(room.getId());
			}
		}
		rooms = roomService.getOnlineRooms();
		roomPacket.setRooms(rooms);
		if (roomPacket.getChildElementXML() != null) {
			Document doc = DocumentHelper.parseText(roomPacket
					.getChildElementXML());
			Element element = doc.getRootElement();
			reply.setChildElement(element.createCopy());
			reply.setType(IQ.Type.result);
		}
	}

	/**
	 * 创建新游戏房间
	 * 
	 * @param reply
	 * @param query
	 * @throws DocumentException
	 */
	private void createRoom(IQ reply, Element query) throws DocumentException {
		String roomXML = StringUtils.unescapeNode(query.elementText("room"));
		Room room = Room.fromXML(roomXML);
		roomService.createRoom(room);
		RoomPacket roomPacket = new RoomPacket();
		roomPacket.setRoom(room);
		if (roomPacket.getChildElementXML() != null) {
			Document doc = DocumentHelper.parseText(roomPacket
					.getChildElementXML());
			Element element = doc.getRootElement();
			reply.setChildElement(element.createCopy());
			reply.setType(IQ.Type.result);
			new Thread(new PushRoomToClientThread(room.getId(), sessionManager))
					.start();
		}
	}

	/**
	 * Returns the namespace of the handler.
	 * 
	 * @return the namespace
	 */
	public String getNamespace() {
		return NAMESPACE;
	}

}
